package wotd;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import net.sf.jsr107cache.Cache;
import net.sf.jsr107cache.CacheException;
import net.sf.jsr107cache.CacheFactory;
import net.sf.jsr107cache.CacheManager;

import com.google.appengine.api.memcache.jsr107cache.GCacheFactory;
import com.google.inject.Inject;
import com.google.inject.Singleton;

@Singleton
public class GCacheVerseLookup implements VerseLookup {
	/** the query engine */
	private final BibleQuery bible;
	
	/** the prng for selecting excerpts */
	private final Random rnd;
	
	/** the list of predefined excerpt references */
	private final List<String> references;
	
	/** the cached verses */
	private Cache verses;
	
	@Inject
	public GCacheVerseLookup(BibleQuery esv) throws IOException {
		this.bible = esv;
		
		rnd = new Random();
		references = new ArrayList<String>(500);

		try {
			CacheFactory cf = CacheManager.getInstance().getCacheFactory();
			Map props = new HashMap();
			props.put(GCacheFactory.EXPIRATION_DELTA, 3600 * 24 * 7);
			verses = cf.createCache(props);
	
			loadReferences();
		} catch (CacheException e) {
			throw new IOException(e);
		}
	}

	@Override
	public String getRandomVerse() throws IOException {
		return getSelectedVerse(selectReference());
	}
	
	@Override
	public String getSelectedVerse(String reference) throws IOException {
		String v = (String) verses.get(reference);
		if (v == null) {
			v = bible.query(reference);
			verses.put(reference, v);
		}
		
		return v;
	}
	
	@Override
	public void getAllVerses(VerseSpooler spooler) throws IOException {
		for (String v : references) {
			spooler.spool(getSelectedVerse(v));
		}
	}
	
	private void loadReferences() throws IOException {
		LineNumberReader lnr = new LineNumberReader(new InputStreamReader(
				getClass().getResourceAsStream("/passages")));
		
		String line;
		while ((line = lnr.readLine()) != null)
			references.add(line);
	}
	
	private synchronized String selectReference() {
		return references.get(rnd.nextInt(references.size()));
	}
}
